package dryven.view.components;

import java.io.Writer;

import dryven.reflection.ClassTypeRef;
import dryven.reflection.TypeRef;
import dryven.util.ArrayIterable;
import dryven.view.StackedViewData;
import dryven.view.ViewDataDictionary;
import dryven.view.engine.component.MultiThreadViewComponent;
import dryven.view.engine.component.ViewComponent;
import dryven.view.engine.component.annotations.ComponentAttribute;
import dryven.view.engine.component.childzone.ChildZoneBindings;
import dryven.view.engine.component.childzone.ChildZoneCallback;
import dryven.view.engine.component.childzone.DefaultChildZoneStrategy;
import dryven.view.engine.component.annotations.ChildZones;
import dryven.view.engine.expression.ViewDataDeclaration;
import dryven.view.engine.expression.nodelisters.ExpressionNodeFactory;
import dryven.view.engine.parser.componentinvocation.AttributeBinding;
import dryven.view.engine.parser.componentinvocation.AttributeBindings;

/**
 * Component to iterate over a java.lang.Iterable
 * 
 * @author bwindels
 *
 */
@ChildZones(strategy=IterateChildZoneStrategy.class)
public class Iterate extends MultiThreadViewComponent {
	
	public void renderComponent(
			ViewDataDictionary localViewData, 
			Writer out, 
			ChildZoneBindings childZones, 
			@ComponentAttribute("each") Iterable<Object> collection,
			@ComponentAttribute("as") String newVariableName)
	{
		StackedViewData vd = new StackedViewData(localViewData);
		ChildZoneCallback childZone = childZones.getChildZoneCallback(ViewComponent.DefaultChildZone);
		for (Object o : collection) {
			vd.set(newVariableName, o);
			childZone.render(vd, out);
		}
	}

}

/**
 * Declares the variablename as defined in the attribute "as" with
 * the component type of the value bound in the attribute "each".
 * @author bwindels
 *
 */
class IterateChildZoneStrategy extends DefaultChildZoneStrategy {

	
	public IterateChildZoneStrategy(){}
	
	@Override
	public Iterable<ViewDataDeclaration> getViewDataDeclarations(
			String name,
			AttributeBindings attributeBindings, 
			ExpressionNodeFactory _expressionFactory) {
		AttributeBinding as = attributeBindings.getBindingByName("as");
		if(!as.isLiteral()) {
			throw new RuntimeException("The name of a variable cannot be a variable itself.");
		}
		String varname = as.getValue(null).toString();

		AttributeBinding each = attributeBindings.getBindingByName("each");
		Class<?> type = each.getBoundGenericType(0);
		TypeRef ref = new ClassTypeRef(type);
		return new ArrayIterable<ViewDataDeclaration>(
			new ViewDataDeclaration[]{
				new ViewDataDeclaration(ref, varname, _expressionFactory.create(ref))
			}
		);
		
	}
	
}
